home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 7 / FM Towns Free Software Collection 7.iso / ms_dos / thbgm / thbgm.c < prev    next >
C/C++ Source or Header  |  1993-11-30  |  10KB  |  471 lines

  1.  
  2. /*
  3.     “THbgm”SNFファイル作成
  4.  
  5.         By 五味
  6.  
  7. */
  8.  
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <conio.h>
  15.  
  16. #define    TRUE    1
  17. #define    FALSE    0
  18.  
  19. #define    REST    0x80
  20. #define    TEMPO    0x90
  21. #define    CONTR    0xa0
  22. #define    VOLCH    0xb0
  23. #define    PITCH    0xc0
  24. #define    PANPO    0xd0
  25. #define    EOC    0x00
  26. #define    LOOP    0xff
  27.  
  28. #define    MAXB        96*4
  29. #define    FBOCT        12
  30. #define    HEADERSIZE    256
  31.  
  32. #define    PARTMAX    6
  33.  
  34.     /* SNFフォーマット    */
  35. struct    snfheader {
  36.     char    name[4];        /* 識別子        */
  37.     char    ver_high;        /* バージョン上位    */
  38.     char    ver_low;        /* バージョン下位    */
  39.     char    reserve1[2];        /* 予約域1        */
  40.     char    title[56];        /* タイトル名        */
  41.  
  42.     char    fmbname[16];        /* FM音源ファイル名    */
  43.     char    reserve2[16];        /* 予約域2        */
  44.     char    applname[32];        /* 作成アプリ名        */
  45.  
  46.     long    dsize[PARTMAX];        /* パートのサイズ    */
  47.     char    reserve3[64-PARTMAX*4];    /* 予約域3        */
  48.  
  49.     char    reserve4[64];        /* 予約域4        */
  50.     } head;
  51.  
  52.     FILE    *part[PARTMAX];        /* パート毎のテンポラリ    */
  53.     char    *titlename=NULL;    /* タイトル名        */
  54.     char    *inputfile=NULL;    /* ソースファイル名    */
  55.     char    *outputfile=NULL;    /* 生成ファイル名    */
  56.     char    *fmbfile="fm_1.fmb";    /* FM音源ファイル名    */
  57.     char    inputname[128];        /* ソースファィル名buf    */
  58.     char    outputname[128];    /* 生成ファイル名buf    */
  59.     char    fmbname[128];        /* FM音源ファイル名buf*/
  60.  
  61.     int    isloop=FALSE;        /* ループさせるか    */
  62.     int    howpart=6;        /* パート数        */
  63.     int    line=1;            /* 行番号        */
  64.     int    block=1;        /* ブロック数        */
  65.  
  66.     int    oct[PARTMAX];        /* オクターブ        */
  67.     int    gate[PARTMAX];        /* ゲートタイム        */
  68.     int    deflen[PARTMAX];    /* デフォルトの長さ    */
  69.     int    volume[PARTMAX];    /* ボリューム        */
  70.     int    all[PARTMAX];        /* 小節毎の長さ        */
  71.  
  72.     char    vel[]={      1,  8, 16, 24, 32, 40, 48, 56,
  73.              64, 72, 80, 88, 96,108,116,127    };
  74.     char    *title=    "  'THbgm' MML compiler\n"
  75.             "  (c) H.Gomi 93/04/04\n";
  76.     char    *usage=    "  [usage] THbgm <input_file> "
  77.             "[-fFMBname][-pPART][-l][-tTITLE][output_file]\n";
  78.     char    *islpmes[]={ "NOLOOP","LOOP"    };
  79.     char    *parterror="  パート数の指定が違法です.\n";
  80.  
  81.     char    *lenpar="  %d: illegal length.\n";
  82.     char    *velpar="  %d: ベロシティ設定が違法です(1~127)\n";
  83.     char    *volpar="  %d: ボリューム設定が違法です(0~15)\n";
  84.     char    *tempar="  %d: テンポ設定が違法です(40~280)\n";
  85.     char    *octpar="  %d: オクターブ指定が違法です(0~8)\n";
  86.     char    *dlnpar="  %d: 省略音長の指定が違法です(1~384)\n";
  87.     char    *gtepar="  %d: ゲートタイムの指定が違法です(0~8)\n";
  88.     char    *ocbpar="  %d: オクターブが下限を越えました\n";
  89.     char    *ocupar="  %d: オクターブが上限を越えました\n";
  90.     char    *cntpar="  %d: 音色変更の指定が違法です(1~128)\n";
  91.     char    *pchpar="  %d: ピッチベンドの指定が違法です(-8192~8191)\n";
  92.     char    *panpar="  %d: パンポッドの指定が違法です(-64~63)\n";
  93.  
  94.  
  95.  
  96. void makeheader(void)
  97. {
  98.     FILE    *fp;
  99.     int    i;
  100.     char    *buf;
  101.  
  102.     if( (fp=fopen(outputfile,"wb"))==NULL ) {
  103.         printf("  can't creat outputfile'%s'.\n",outputfile);
  104.         exit(1);
  105.     }
  106.  
  107.     memset(&head,'\0',HEADERSIZE);
  108.     strcpy(head.name,"SNF");
  109.     head.ver_high=1;
  110.     head.ver_low =0;
  111.     strcpy(head.fmbname,fmbfile);
  112.     for( i=0 ; i<howpart ; i++ )
  113.         head.dsize[i]=(long)ftell(part[i]);
  114.     strcpy(head.applname,"THbgm v1.0");
  115.     if( titlename )    strcpy(head.title,titlename);
  116.         else    strcpy(head.title,"some piece");
  117.  
  118.     fwrite(&head,HEADERSIZE,1,fp);
  119.  
  120.     printf("----------<%s>----------\n",outputfile);
  121.     printf(" TITLE       : %s\n",titlename);
  122.     printf(" FMBfile     : %s\n",fmbfile);
  123.     printf(" SRCfile     : %s\n",inputfile);
  124.     printf(" PART        : %d\n",howpart);
  125.     printf(" BLOCK       : %d\n",block);
  126.     printf(" LOOP        : %s\n",islpmes[isloop]);
  127.     printf(" APPLICATION : %s\n",head.applname);
  128.     printf(" (SNF format v%d.%d)\n",head.ver_high,head.ver_low);
  129.     printf("------------------------------\n");
  130.  
  131.     for( i=0 ; i<howpart ; i++ ) {
  132.         fseek(part[i],0,SEEK_SET);
  133.         if( (buf=malloc(head.dsize[i]))==NULL ) {
  134.             printf("  メモリが足りません.\n");
  135.             exit(1);
  136.         }
  137.         if( fread(buf,(size_t)head.dsize[i],1,part[i])==0 ||
  138.            fwrite(buf,(size_t)head.dsize[i],1,fp)==0        ) {
  139.             printf("  read & write failed.\n");
  140.             exit(1);
  141.         }
  142.     }
  143.  
  144.     printf("  completed.\n");
  145.     exit(0);
  146. }
  147.  
  148.  
  149. char eget(FILE *fp)        /* エラー処理付ストリーム入力    */
  150. {
  151.     int    ll;
  152.  
  153.     if( (ll=fgetc(fp))==EOF ) {
  154.         if( ferror(fp) ) {
  155.             printf("  accident: file error.\n");
  156.             exit(2);
  157.         }else{
  158.             fclose(fp);
  159.             printf("  total %d blocks.\t\t\t\t\n",block);
  160.             makeheader();
  161.         }
  162.     }
  163.     return((char)ll);
  164. }
  165.  
  166. void eunget(char c,FILE *fp)    /* エラー処理付ungetc    */
  167. {
  168.     if( ungetc((int)c,fp)==EOF ) {
  169.         printf("  fatal: streem error.\n");
  170.         exit(3);
  171.     }
  172. }
  173.  
  174. int egetnum(FILE *fp)        /* ストリームから数値入力    */
  175. {
  176.     int    c,ll,sn;
  177.  
  178.     if( (c=eget(fp))!='+' )
  179.         eunget(c,fp);
  180.  
  181.     if( (c=eget(fp))=='-' )
  182.         sn=TRUE;
  183.     else{
  184.         sn=FALSE;
  185.         eunget(c,fp);
  186.     }
  187.  
  188.     for( ll=0 ; ; ) {
  189.         c=eget(fp);
  190.         if( !isdigit(c) )    break;
  191.         ll=ll*10+(c-'0');
  192.     }
  193.     eunget(c,fp);
  194.     if( sn==TRUE )    return -ll;
  195.         else    return  ll;
  196. }
  197.  
  198. void comerr(char *mes)        /* エラーメッセージ表示と終了    */
  199. {
  200.     printf(mes,line);
  201.     exit(1);
  202. }
  203.  
  204.  
  205.  
  206. void makesnf(void)        /* MMLコンパイラメイン    */
  207. {
  208.     FILE    *fp;
  209.     int    i;
  210.     char    c;
  211.     int    nowpart;            /* 現在処理中のパート    */
  212.     int    code,rest,leap,len,key,val;    /* 各種テンポラリ    */
  213.     char    tbuf[128];            /* 汎用buf        */
  214.  
  215.     if( (fp=fopen(inputfile,"r"))==NULL ) {
  216.         printf("  can't open'%s'.\n",inputfile);
  217.         exit(1);
  218.     }
  219.  
  220.     for( i=0 ; i<howpart ; i++ ) {
  221.         if( (part[i]=tmpfile())==NULL ) {
  222.             printf("  creating temporary file failed.\n");
  223.             exit(1);
  224.         }
  225.     }
  226.  
  227.     for( i=0 ; i<howpart ; i++ ) {
  228.         oct[i]   = 4;
  229.         gate[i]  = 7;
  230.         deflen[i]= 4;
  231.         volume[i]= vel[15];
  232.         all[i]   = 0;
  233.     }
  234.  
  235.  
  236.     while(TRUE)
  237.     for( nowpart=0 ; nowpart<howpart ; ) {
  238.         code=0;rest=0;
  239.         switch(tolower(eget(fp))) {
  240.         case' ':
  241.         case'\t':
  242.             break;
  243.         case'/':
  244.             while( eget(fp)!='\n' );
  245.             line++;
  246.             break;
  247.         case'\n':
  248.             line++;
  249.             if( ++nowpart==howpart ) {
  250.                 nowpart=0;
  251.                 len=0;
  252.                 for( i=0 ; i<howpart ; i++ )
  253.                     if( len<all[i] )
  254.                         len=all[i];
  255.                 for( i=0 ; i<howpart ; i++ ) {
  256.                     if( all[i]<len ) {
  257.                         putc(REST,part[i]);
  258.                         putw(len-all[i],part[i]);
  259.                     }
  260.                 }
  261.                 for( i=0 ; i<howpart ; i++ )
  262.                     all[i]=0;
  263.         sprintf(tbuf,"  %03d block done(step %d).%c",block++,len,0xd);
  264.         cputs(tbuf);
  265.             }
  266.             break;
  267.         case'v':
  268.             if( (c=eget(fp))=='@' ) {
  269.                 val=egetnum(fp);
  270.                 if( val<1 || 127<val )
  271.                     comerr(velpar);
  272.             }else{
  273.                 eunget(c,fp);
  274.                 val=egetnum(fp);
  275.                 if( val<0 || 15<val )
  276.                     comerr(volpar);
  277.                 val=vel[val];
  278.             }
  279.             volume[nowpart]=val;
  280.             putc(VOLCH,    part[nowpart]);
  281.             putc((char)val,    part[nowpart]);
  282.             break;
  283.         case't':
  284.             val=egetnum(fp);
  285.             if( val<40 || 280<val )
  286.                 comerr(tempar);
  287.             putc(TEMPO,        part[nowpart]);
  288.             putc((char)(val-30),    part[nowpart]);
  289.             break;
  290.         case'o':
  291.             val=egetnum(fp);
  292.             if( val<0 || 8<val )
  293.                 comerr(octpar);
  294.             oct[nowpart]=val;
  295.             break;
  296.         case'l':
  297.             val=egetnum(fp);
  298.             if( val<1 || MAXB<val )
  299.                 comerr(dlnpar);
  300.             deflen[nowpart]=val;
  301.             break;
  302.         case'q':
  303.             val=egetnum(fp);
  304.             if( val<1 || 8<val )
  305.                 comerr(gtepar);
  306.             gate[nowpart]=val;
  307.             break;
  308.         case'<':
  309.             if( --oct[nowpart]<0 )
  310.                 comerr(ocbpar);
  311.             break;
  312.         case'>':
  313.             if( ++oct[nowpart]>8 )
  314.                 comerr(ocupar);
  315.             break;
  316.         case'@':
  317.             val=egetnum(fp);
  318.             if( val<1 || 128<val )
  319.                 comerr(cntpar);
  320.             putc(CONTR,        part[nowpart]);
  321.             putc((char)(val-1),    part[nowpart]);
  322.             break;
  323.         case'u':
  324.             val=egetnum(fp);
  325.             if( val<-8192 || 8191<val )
  326.                 comerr(pchpar);
  327.             putc(PITCH,    part[nowpart]);
  328.             putw(val,    part[nowpart]);
  329.             break;
  330.         case'p':
  331.             val=egetnum(fp);
  332.             if( val<-64 || 63<val )
  333.                 comerr(panpar);
  334.             putc(PANPO,        part[nowpart]);
  335.             putc((char)(val+64),    part[nowpart]);
  336.             break;
  337.  
  338.  
  339.         case'r':
  340.             rest=1;
  341.         case'b':
  342.             code++;
  343.             code++;
  344.         case'a':
  345.             code++;
  346.             code++;
  347.         case'g':
  348.             code++;
  349.             code++;
  350.         case'f':
  351.             code++;
  352.         case'e':
  353.             code++;
  354.             code++;
  355.         case'd':
  356.             code++;
  357.             code++;
  358.         case'c':
  359.             c=eget(fp);
  360.             if( c=='+' )    code++;
  361.             else if(c=='-')    code--;
  362.             else        eunget(c,fp);
  363.             leap=0;
  364.             do {
  365.                 c=eget(fp);eunget(c,fp);
  366.                 if( isdigit(c) ) {
  367.                     len=egetnum(fp);
  368.                     if( len<1 || MAXB<len )
  369.                         comerr(lenpar);
  370.                 }else    len=deflen[nowpart];
  371.                 leap=MAXB/len;
  372.                 if( (c=eget(fp))=='.' )    leap+=(MAXB/2)/len;
  373.                     else        eunget(c,fp);
  374.             }while( (c=eget(fp))=='&' );
  375.             eunget(c,fp);
  376.             if( rest ) {
  377.                 putc(REST,part[nowpart]);
  378.                 putw(leap,part[nowpart]);
  379.             }else{
  380.                 key=(leap*gate[nowpart])/8;
  381.                 putc(code+oct[nowpart]*12+FBOCT,part[nowpart]);
  382.                 putw(key,            part[nowpart]);
  383.                 if( key<leap ) {
  384.                     putc(REST,    part[nowpart]);
  385.                     putw(leap-key,    part[nowpart]);
  386.                 }
  387.             }
  388.             all[nowpart]+=leap;
  389.             break;
  390.         default:
  391.             printf("  %d: illegal charactor'%c'.\n",line,c);
  392.             exit(1);
  393.         }
  394.     }
  395.  
  396. }
  397.  
  398.  
  399. void main(int argc,char *argv[])    /* メイン    */
  400. {
  401.     int    cm;
  402.     char    *p;
  403.  
  404.     printf(title);
  405.  
  406.     for( cm=1 ; cm<argc ; cm++ ) {
  407.         if( *argv[cm]=='-' ) {
  408.             switch(*(argv[cm]+1)) {
  409.             case'h':
  410.             case'H':
  411.             case'?':
  412.                 printf(usage);
  413.                 exit(0);
  414.             case'f':
  415.                 fmbfile=argv[cm]+2;
  416.                 break;
  417.             case'l':
  418.                 isloop=TRUE;
  419.                 break;
  420.             case'p':
  421.                 howpart=atoi(argv[cm]+2);
  422.                 if( howpart<0 || howpart>PARTMAX ) {
  423.                     printf(parterror);
  424.                     exit(1);
  425.                 }
  426.                 break;
  427.             case't':
  428.                 titlename=argv[cm]+2;
  429.                 break;
  430.             default:
  431.                 printf("  illegal option'%s'.\n",argv[cm]);
  432.                 exit(1);
  433.             }
  434.         }else if( inputfile ==NULL ) {
  435.             inputfile =argv[cm];
  436.         }else if( outputfile==NULL ) {
  437.             outputfile=argv[cm];
  438.         }else {
  439.             printf("  too much file'%s'.\n",argv[cm]);
  440.             exit(1);
  441.         }
  442.     }
  443.  
  444.  
  445.     if( inputfile ==NULL ) {
  446.         printf("  no inputfile.\n");
  447.         exit(2);
  448.     }
  449.     if( strchr(inputfile,'.')==NULL ) {
  450.         strcpy(inputname,inputfile);
  451.         strcat(inputname,".mml");
  452.         inputfile=inputname;
  453.     }
  454.     if( outputfile==NULL ) {
  455.         strcpy(outputname,inputfile);
  456.         outputfile=outputname;
  457.         if( (p=strchr(outputfile,'.'))==NULL ) {
  458.             strcat(outputfile,".snf");
  459.         }else{
  460.             strcpy(p,".snf");
  461.         }
  462.     }
  463.     if( strchr(fmbfile,'.')==NULL ) {
  464.         strcpy(fmbname,fmbfile);
  465.         strcat(fmbname,".fmb");
  466.         fmbfile=fmbname;
  467.     }
  468.  
  469.     makesnf();
  470. }
  471.